﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using System.Reflection;
using System.Security.Claims;

namespace Framework.Core
{
	/// <summary>
	/// 
	/// </summary>
	public static class App
	{
		private static WebApplication? _webApplication;
		private static IHttpContextAccessor? _httpContextAccessor;
		private static WebApplicationBuilder? _webApplicationBuilder;
		private static IServiceCollection? _serviceCollection;
		private static readonly List<IStartupModule> StartupList = [];
		private static readonly List<string> UrlList = [];
		private static readonly AppOptions AppOptionsObject = new();
		private static readonly object LockObj = new();

		/// <summary>
		/// IServiceCollection
		/// </summary>
		public static IServiceCollection? Services => _serviceCollection;

		/// <summary>
		/// IHost
		/// </summary>
		public static IHost? Host => _webApplication;

		/// <summary>
		/// HttpContext
		/// </summary>
		public static HttpContext? HttpContext => CatchOrDefault(() => ServiceProvider?.GetService<IHttpContextAccessor>()?.HttpContext);

		/// <summary>
		/// IServiceProvider
		/// </summary>
		public static IServiceProvider? ServiceProvider => _webApplication?.Services;

		/// <summary>
		/// 程序启动器集合
		/// </summary>
		public static IStartupModule[] Startups => StartupList.ToArray();

		/// <summary>
		/// 程序启动地址
		/// </summary>
		public static string[] Urls => UrlList.ToArray();

		/// <summary>
		/// WebApplication
		/// </summary>
		public static WebApplication? WebApplication => _webApplication;

		/// <summary>
		/// WebApplicationBuilder
		/// </summary>
		public static WebApplicationBuilder? WebApplicationBuilder => _webApplicationBuilder;

		/// <summary>
		/// App 配置项
		/// </summary>
		public static AppOptions AppOptions => AppOptionsObject;

		/// <summary>
		/// 创建服务域
		/// </summary>
		/// <returns></returns>
		public static IServiceScope? CreateScope() => _webApplication?.Services?.CreateScope();

		/// <summary>
		/// 全局配置选项
		/// </summary>
		public static IConfiguration Configuration { get; set; }

		/// <summary>
		/// 应用有效程序集
		/// </summary>
		public static readonly List<Assembly> Assemblies;

		/// <summary>
		/// 获取请求上下文用户
		/// </summary>
		/// <remarks>只有授权访问的页面或接口才存在值，否则为 null</remarks>
		public static ClaimsPrincipal User => HttpContext?.User;

		public static void iniApp(IServiceCollection Services, WebApplication app)
		{
			_webApplication = app;
			_serviceCollection = Services;
		}

		/// <summary>
		/// 添加 StartupModule 
		/// </summary>
		/// <typeparam name="TStartupModule"></typeparam>
		/// <param name="builder"></param>
		/// <param name="options"></param>
		/// <returns></returns>
		public static WebApplicationBuilder AddStartupModule<TStartupModule>(
			this WebApplicationBuilder builder,
			Action<AppOptions>? options = null
		)
			where TStartupModule : IStartupModule
		{
			lock (LockObj)
			{
				_webApplicationBuilder = builder;
				_serviceCollection = builder.Services;
				Configuration = builder.Configuration;
				
				if (Activator.CreateInstance(typeof(TStartupModule)) is IStartupModule startup)
				{
					StartupList.Clear();

					var allImportStartup = startup?.GetAllImportStartup();

					var appStartupsOrderBy = allImportStartup?.OrderBy(w => w.Order).ToList();

					if (appStartupsOrderBy != null && appStartupsOrderBy.Count > 0)
					{
						StartupList.AddRange(appStartupsOrderBy);
					}

					foreach (var item in StartupList)
					{
						item?.ConfigureServices(builder);
					}
				}
			}

			options?.Invoke(AppOptionsObject);

			AppOptionsObject.WebApplicationBuilderAction?.Invoke(builder);

			return builder;
		}

		/// <summary>
		/// 开始启动 framework 
		/// </summary>
		/// <param name="app"></param>
		/// <returns></returns>
		public static async Task StartFrameworkAsync(this WebApplication app)
		{
			_webApplication ??= app;

			var hostApplicationLifetime = app.Services.GetService<IHostApplicationLifetime>();
			if (hostApplicationLifetime == null) return;

			// 启动
			hostApplicationLifetime.ApplicationStarted.Register(() =>
			{
				UrlList.AddRange(app.Urls.ToList());

				foreach (var item in App.Startups)
				{
					item?.ApplicationStarted(app);
				}
			});
			
			// 停止中
			hostApplicationLifetime.ApplicationStopping.Register(() =>
			{
				foreach (var item in App.Startups)
				{
					item?.ApplicationStopping(app);
				}
			});

			// 已停止
			hostApplicationLifetime.ApplicationStopped.Register(() =>
			{
				foreach (var item in App.Startups)
				{
					item?.ApplicationStopped(app);
				}
			});

			//App._httpContextAccessor = App.ServiceProvider.GetService<IHttpContextAccessor>();

			foreach (var item in App.Startups)
			{
				item?.Configure(app);
			}

			AppOptionsObject?.WebApplicationAction?.Invoke(app);
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		static App()
		{
			// 加载程序集
			var assObject = AssemblyUtil.GetAssemblyList();
			Assemblies = assObject.ToList();

			// 获取有效的类型集合
			EffectiveTypes = Assemblies.SelectMany(GetTypes).ToList();
		}

		/// <summary>
		/// 加载程序集中的所有类型
		/// </summary>
		/// <param name="ass"></param>
		/// <returns></returns>
		private static IEnumerable<Type> GetTypes(Assembly ass)
		{
			var types = Array.Empty<Type>();

			try
			{
				types = ass.GetTypes();
			}
			catch
			{
				Console.WriteLine($"Error load `{ass.FullName}` assembly.");
			}

			return types.Where(u => u.IsPublic);
		}

		/// <summary>
		/// 获取选项
		/// </summary>
		/// <typeparam name="TOptions">强类型选项类</typeparam>
		/// <param name="serviceProvider"></param>
		/// <returns>TOptions</returns>
		public static TOptions GetOptions<TOptions>(IServiceProvider serviceProvider = default)
			where TOptions : class, new()
		{
			return GetRequiredService<IOptions<TOptions>>().Value;
		}

		/// <summary>
		/// 获取配置
		/// </summary>
		/// <typeparam name="TOptions">强类型选项类</typeparam>
		/// <param name="path">配置中对应的Key</param>
		/// <param name="loadPostConfigure"></param>
		/// <returns>TOptions</returns>
		public static TOptions GetConfig<TOptions>(string path, bool loadPostConfigure = false)
		{
			var options = Configuration.GetSection(path).Get<TOptions>();

			return options;
		}

		/// <summary>
		/// 有效程序集类型
		/// </summary>
		public static readonly List<Type> EffectiveTypes;

		/// <summary>
		/// 处理获取对象异常问题
		/// </summary>
		/// <typeparam name="T">类型</typeparam>
		/// <param name="action">获取对象委托</param>
		/// <param name="defaultValue">默认值</param>
		/// <returns>T</returns>
		private static T CatchOrDefault<T>(Func<T> action, T defaultValue = null)
			where T : class
		{
			try
			{
				return action();
			}
			catch
			{
				return defaultValue ?? null;
			}
		}

		/// <summary>
		/// 获取请求生命周期的服务
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public static IServiceProvider GetRequiredService(Type type)
		{
			//if(ServiceProvider != null)
			//{
			//	return ServiceProvider.GetRequiredService(type);
			//}
			//else
			//{
			//	return null;
			//}

			// 第一选择，判断是否是单例注册且单例服务不为空，如果是直接返回根服务提供器
			if (ServiceProvider != null && Services.Where(u => u.ServiceType == (type.IsGenericType ? type.GetGenericTypeDefinition() : type))
																	.Any(u => u.Lifetime == ServiceLifetime.Singleton)) return ServiceProvider;

			// 第二选择是获取 HttpContext 对象的 RequestServices
			var httpContext = HttpContext;
			if (httpContext?.RequestServices != null) return httpContext.RequestServices;
			// 第三选择，创建新的作用域并返回服务提供器
			else if (ServiceProvider != null)
			{
				var scoped = ServiceProvider.CreateScope();
				//UnmanagedObjects.Add(scoped);
				return scoped.ServiceProvider;
			}
			// 第四选择，构建新的服务对象（性能最差）
			else
			{
				var serviceProvider = Services.BuildServiceProvider();
				//UnmanagedObjects.Add(serviceProvider);
				return serviceProvider;
			}
		}

		/// <summary>
		/// 获取请求生命周期的服务
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <returns></returns>
		public static TService GetRequiredService<TService>()
			where TService : class
		{
			return GetRequiredService(typeof(TService)).GetRequiredService(typeof(TService)) as TService;
		}

		// <summary>
		/// 获取请求生存周期的服务
		/// </summary>
		/// <typeparam name="TService"></typeparam>
		/// <param name="serviceProvider"></param>
		/// <returns></returns>
		public static TService GetService<TService>(IServiceProvider serviceProvider = default)
			where TService : class
		{
			return GetService(typeof(TService), serviceProvider) as TService;
		}

		/// <summary>
		/// 获取请求生存周期的服务
		/// </summary>
		/// <param name="type"></param>
		/// <param name="serviceProvider"></param>
		/// <returns></returns>
		public static object GetService(Type type, IServiceProvider serviceProvider = default)
		{
			return (serviceProvider ?? GetServiceProvider(type)).GetService(type);
		}

		/// <summary>
		/// 解析服务提供器
		/// </summary>
		/// <param name="serviceType"></param>
		/// <returns></returns>
		public static IServiceProvider GetServiceProvider(Type serviceType)
		{
			// 第一选择，判断是否是单例注册且单例服务不为空，如果是直接返回根服务提供器
			if (ServiceProvider != null && Services.Where(u => u.ServiceType == (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType))
																	.Any(u => u.Lifetime == ServiceLifetime.Singleton)) return ServiceProvider;

			// 第二选择是获取 HttpContext 对象的 RequestServices
			var httpContext = HttpContext;
			if (httpContext?.RequestServices != null) return httpContext.RequestServices;
			// 第三选择，创建新的作用域并返回服务提供器
			else if (ServiceProvider != null)
			{
				var scoped = ServiceProvider.CreateScope();
				//UnmanagedObjects.Add(scoped);
				return scoped.ServiceProvider;
			}
			// 第四选择，构建新的服务对象（性能最差）
			else
			{
				var serviceProvider = Services.BuildServiceProvider();
				//UnmanagedObjects.Add(serviceProvider);
				return serviceProvider;
			}
		}
	}
}
